package com.DT.netTool

import android.Manifest
import android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.Rect
import android.location.LocationManager
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.provider.Settings
import android.text.method.ScrollingMovementMethod
import android.util.Log
import android.view.DisplayCutout
import android.view.View
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.WindowInsets
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.AdapterView
import android.widget.TableRow
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.example.network.BuildConfig
import com.example.network.R
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.data.*
import com.github.mikephil.charting.formatter.PercentFormatter
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
import kotlinx.android.synthetic.main.activity_main.*
import org.jetbrains.anko.alert
import org.json.JSONObject.NULL
import java.io.BufferedReader
import java.io.FileReader
import java.io.IOException
import java.lang.reflect.Method
import java.net.*
import java.util.*
import kotlin.collections.ArrayList


const val PINGMSG=9999
const val PINGRUN=0
const val ARPMSG=1
const val ARPRUN=2
const val ARPPER=3
const val TRACEMSG=5
const val TRACERUN=6
const val WIFIINFO=10

enum class Tool(aa: Int){
    PING(0),
    ARP(1),
    NMAP(2),
    TRACETOUTE(3)
}

var UsingTool=Tool.PING

class MainActivity : AppCompatActivity() {
    private lateinit var pingThread: Thread
    private lateinit var arpThread: Thread
    private lateinit var traceThread: Thread
    private lateinit var pingMember: PingNetUtil

    private var myWifiName: String? = null
    private var myIp : String=""
    private var myMac: String? = null
    private var traceRoute= traceRoute()

    private lateinit var myLinechart:lineChart
    private lateinit var myPiechart:pieChart



    /*消息处理，负责处理来自子线程的消息，更新到textView上面*/
    var mHandler:Handler= @SuppressLint("HandlerLeak")
    object: Handler(){
        var arpRead=false
          override fun handleMessage(msg: Message?){
            super.handleMessage(msg)
            when(msg?.what){
                PINGRUN -> {
                    var str = msg.obj as String
                    if (str == "start")
                        button.text = resources.getString(R.string.button_stop)
                    else if (str == "stop")
                        button.text = resources.getString(R.string.button_ping)

                    //Toast.makeText(applicationContext,"子线程消息",Toast.LENGTH_LONG).show()//弹出消息
                }
                PINGMSG -> {
                    var str = msg.obj as String
                    var count = 0
                    var time = 0.0f

                    textshow.append(str)
                    refreshTextView(textshow)

                    if (str.indexOf("time=") > 0) {
                        count = str.substring(str.indexOf("icmp_seq=") + 9!!, str.indexOf(" ttl=")!!).toInt()
                        time = str.substring(str.indexOf("time=") + 5!!, str.indexOf(" ms")!!).toFloat()
                        myPiechart.recvPacket++
                    } else if (str.indexOf("icmp_seq=") > 0) {
                        count = str.substring(
                                str.indexOf("icmp_seq=") + 9!!,
                                str.indexOf(" Destination")!!
                        ).toInt()
                        time = 0f
//                            Log.d(
//                                "data",
//                                "count:" + count + ", lossPacket=" + myPiechart.lossPacket
//                            )
                        myPiechart.lossPacket++

                    }
                    if (count > 0) {
                        myPiechart.setData()
//                        chart2.invalidate()
                    }
                    myLinechart.setData(count, time)
//                    chart1.invalidate()

                }
                ARPMSG -> {
                    /*解析行内容*/
                    var line: String = msg.obj as String
                    Log.d("line", line)

                    var row = TableRow(applicationContext)
                    var name = TextView(applicationContext)
                    var IP = TextView(applicationContext)
                    var MAC = TextView(applicationContext)

                    var strarray = line.split("\t");
                    name.text = strarray[0]
                    IP.text = strarray[1]
                    MAC.text = strarray[2]

                    if (strarray[1].isEmpty() || strarray[1] == "") return

                    row.addView(name)
                    row.addView(IP)
                    row.addView(MAC)
                    tableShow?.addView(row)
                }
                ARPRUN -> {
                    var str = msg.obj as String
                    if (str == "start") {
                        button3.setEnabled(false)
                        arpRead = true
                    } else if (str == "stop") {
                        arpRead = false
                        button3.setEnabled(true)
                        button3.text = resources.getString(R.string.button_arp)
                    } else if (str == "reflash") {

                        tableShow?.removeAllViews()
                        var name = TextView(applicationContext)
                        var row = TableRow(applicationContext)
                        var IP = TextView(applicationContext)
                        var MAC = TextView(applicationContext)
                        name.text = "NAME"
                        IP.text = "IP"
                        MAC.text = "MAC"

                        row.addView(name)
                        row.addView(IP)
                        row.addView(MAC)
                        tableShow?.addView(row)
                    } else if (str == "killOther") {

                        if (pingMember.isRun()) alert("检测到上一个指令还在执行，将其强行停止？", "") {
                            positiveButton("是") {
                                pingMember.clearProcess()
                            }
                            negativeButton("否") {
//                                arpThread.destroy()
                                button3.setEnabled(true)
                            }
                        }.show()
                    }


                }
                ARPPER -> {
                    if (arpRead) {
                        var per = msg.obj as String
                        button3.text = per + "%"
                    }
                }

                TRACEMSG -> {
                    /*解析行内容*/
                    var line: String = msg.obj as String
//                    Log.w("line",line)

                    textshow.append(line)
                }

                TRACERUN -> {
                    var str = msg.obj as String
                    if (str == "start") {
                        button4.text = resources.getString(R.string.button_stop)
                        textshow.text = ""
                    } else if (str == "stop")
                        button4.text = resources.getString(R.string.button_traceroute)

                    //Toast.makeText(applicationContext,"子线程消息",Toast.LENGTH_LONG).show()//弹出消息
                }

                WIFIINFO -> {
                    var str: String = msg.obj as String
                    wifiInfo?.text = str
                }

            }

        }
    }


    /*键盘处理接口，弹出或者收起虚拟键盘*/
    object KeyboardktUtils{
        fun showKeyboard(view: View) {
            val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                view?.requestFocus()
                imm?.showSoftInput(view, 0)

        }

        fun hideKeyboard(view: View) {
            val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm?.hideSoftInputFromWindow(view.windowToken, 0)
        }

        fun toggleSoftInput(view: View) {
            val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm?.toggleSoftInput(0, 0)
        }
    }

    /*实现ping子线程运行*/
    private fun pingFun(IP: String, Count: String, WaitTime: String){
        pingThread=Thread(Runnable {
            kotlin.run {
//                    button.text ="停止"
                var msg = Message()
                msg.what = PINGRUN
                msg.obj = "start"
                mHandler.sendMessage(msg)

                pingMember.ping(IP, Count, WaitTime, mHandler)

                msg = Message()
                msg.what = PINGRUN
                msg.obj = "stop"
                mHandler.sendMessage(msg)

            }
        })

    }

    /*实现arp子线程运行*/
    private fun arpFun(readTable: Boolean){

//        Log.d("arp","run")

        arpThread=Thread(Runnable {
            kotlin.run {
//                Log.w("arp","runing "+readTable)
                var msg: Message
                var buf: String

                if (readTable) {
                    msg = Message()
                    msg.what = ARPRUN
                    msg.obj = "start"
                    mHandler.sendMessage(msg)
//                    Log.w("arp", "Thread")

                    buf = getNetworkInfo()
                    discover(myIp, 500) // 发送arp请求

                    msg = Message()
                    msg.what = ARPRUN
                    msg.obj = "stop"
                    mHandler.sendMessage(msg)

                    msg = Message()
                    msg.what = ARPRUN
                    msg.obj = "reflash"
                    mHandler.sendMessage(msg)

                    var sendMsg = Message()
                    sendMsg.what = ARPMSG
                    sendMsg.obj = buf
                    mHandler.sendMessage(sendMsg)

                    readArp()
                } else {
                    msg = Message()
                    msg.what = ARPRUN
                    msg.obj = "start"
                    mHandler.sendMessage(msg)

                    getNetworkInfo()
                    discover(myIp, 500) // 发送arp请求


                    msg = Message()
                    msg.what = ARPRUN
                    msg.obj = "stop"
                    mHandler.sendMessage(msg)
                }

            }
        })
//        Log.w("arp","after "+arpThread?.isAlive)

    }
    private fun traceFun(){

        traceThread=Thread(Runnable {

            kotlin.run {
                var dstIP: String
                var dstTime = ""
                var routeIP: String

                var msg = Message()
                msg.what = TRACERUN
                msg.obj = "start"
                mHandler.sendMessage(msg)

                traceRoute.start()

                dstIP = traceRoute.getIP(editText.text.toString(), 0)
                Log.w("trace", "dstIP:" + dstIP)

                msg = Message()
                msg.what = TRACEMSG
                msg.obj = "Traceroute " + dstIP + ": \n"
                mHandler.sendMessage(msg)
//                textshow.text="Traceroute "+dstIP+": \n"
                for (i in 1..30) {
                    if (traceThread.isInterrupted()) {
                        Log.w("stop", "Interrupted")
                        break
                    }
                    try {

                        routeIP = ""
                        dstTime = ""

                        routeIP = traceRoute.getIP(dstIP, i)
                        if (routeIP == "killed") Log.d("trace", "killed")
                        else if (routeIP.isEmpty() || routeIP == "")
                            routeIP = "* * *"
                        else
                            dstTime = traceRoute.getDstTime(routeIP)

                        if (dstTime == "killed" || routeIP == "killed") {
                            msg = Message()
                            msg.what = TRACEMSG
                            msg.obj = "Operation interrupted!\n"
                            mHandler.sendMessage(msg)
                            break
                        }


                        Log.w("trace", i.toString() + "OUT: " + routeIP + " " + dstTime)

                        msg = Message()
                        msg.what = TRACEMSG
                        msg.obj = routeIP + " \t" + dstTime + "\n"
                        mHandler.sendMessage(msg)

                        if (routeIP == dstIP) {
                            msg = Message()
                            msg.what = TRACEMSG
                            msg.obj = "Destination address " + routeIP + " reached!\n"
                            mHandler.sendMessage(msg)
                            break
                        }

                    } catch (e: InterruptedException) {
                        Log.w("stop", "Interrupted")
                        e.printStackTrace();
                        break;//捕获到异常之后，执行break跳出循环。
                    }
                }

                msg = Message()
                msg.what = TRACERUN
                msg.obj = "stop"
                mHandler.sendMessage(msg)

            }
        })

    }


    /**
     * 刷新textView的位置（主要用于textView的自动滚动）
     */
    fun refreshTextView(text: TextView) {
//        Log.d("debug scroll","lineCount:"+text.lineCount+" lineHeight"+text.lineHeight+" text.height"+text.height)
        val offset: Int = text.lineCount * text.lineHeight
        var textHeight:Int
        if (text.maxLines > 0)
            textHeight=(text.maxLines * text.lineHeight)
        else
            textHeight=text.height

        if (offset+text.lineHeight > textHeight ) {
            text.scrollTo(0, offset - textHeight + text.lineHeight)
        }
    }


    /**
     * 跳转到权限设置界面
     */
    private fun getAppDetailSettingIntent() {

        var intent = Intent(Settings.ACTION_LOCALE_SETTINGS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivityForResult(intent, 1);

        /*val intent = Intent("com.meizu.safe.security.SHOW_APPSEC")
        intent.addCategory(Intent.CATEGORY_DEFAULT)
        intent.putExtra("packageName", BuildConfig.APPLICATION_ID)
        try {
            startActivity(intent)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }*/
    }

    /**
     * 判断GPS是否开启，GPS或者AGPS开启一个就认为是开启的
     *
     * @param context 上下文
     * @return true 表示开启
     */

    fun  GPSisOpen(context: Context): Boolean {
        var locationManager:LocationManager =
            context.getSystemService(Context.LOCATION_SERVICE) as LocationManager;
        // 通过GPS卫星定位，定位级别可以精确到街（通过24颗卫星定位，在室外和空旷的地方定位准确、速度快）
        var gps:Boolean = Objects.requireNonNull(locationManager).isProviderEnabled(LocationManager.GPS_PROVIDER);
        // 通过WLAN或移动网络(3G/2G)确定的位置（也称作AGPS，辅助GPS定位。主要用于在室内或遮盖物（建筑群或茂密的深林等）密集的地方定位）
        var network:Boolean = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        return gps || network;
    }

    /**
     * 动态申请权限
     */
    fun handlePermisson(){

        // 需要动态申请的权限
        val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION, ACCESS_BACKGROUND_LOCATION, Manifest.permission.ACCESS_WIFI_STATE)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,
                    ACCESS_BACKGROUND_LOCATION
            ), 101)
        } else {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 101)
        }

        //查看是否已有权限
        for ( permission in permissions) {
            val checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission)

            if (checkSelfPermission == PackageManager.PERMISSION_GRANTED) {
                //已经获取到权限  获取用户媒体资源
                return

            } else {

                //没有拿到权限  是否需要在第二次请求权限的情况下
                // 先自定义弹框说明 同意后在请求系统权限(就是是否需要自定义DialogActivity)
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {

                    myRequestPermission(permissions)

                } else {
                    myRequestPermission(permissions)
                }
            }
        }
    }

    private fun myRequestPermission(permissions: Array<String>) {
        //可以添加多个权限申请
        val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
        requestPermissions(permissions, 1)
    }

    /***
     * 权限请求结果  在Activity 重新这个方法 得到获取权限的结果  可以返回多个结果
     */
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        //是否获取到权限
//        Log.d("try","是否获取到权限")
        if(grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED){

            Log.d("try", "你要实现的业务逻辑")
        }
    }


    /**
     * 获取当前WIFI名称
     *
     * @param context 上下文
     * @return
     */
    fun  getCurrentSsid(context: Context) :String{
        var ssid = "unknown id"

//        Log.d("____SSID","getCurrentSsid")

        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O
            || Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
//            Log.d("____SSID","if")

            var wifiManager:WifiManager =  context.getApplicationContext().getSystemService(Context.WIFI_SERVICE) as WifiManager

            var info:WifiInfo = wifiManager?.connectionInfo

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                ssid = info.ssid
            } else {
                ssid = info.ssid.replace("\"", "")
            }
//            Log.d("____SSID","if2")

            //部分手机拿不到WiFi名称
            var networkId:Int = info.networkId
            var ConfiguredNetworks = wifiManager?.configuredNetworks
//            Log.d("config",ConfiguredNetworks.toString())

            for (config in ConfiguredNetworks ){
//                Log.d("config.networkId",config.networkId.toString()+"  SSID:"+config.SSID)
//                Log.d("networkId",networkId.toString())
//                Log.d("config",config.toString())

                if (config.networkId == networkId) {
                    ssid = config.SSID

                    break
                }
            }
            return ssid
        } else {
//            Log.d("____SSID","else")

            var connManager:ConnectivityManager=  context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

            var networkInfo:NetworkInfo = connManager?.activeNetworkInfo
            if (networkInfo.isConnected()) {
                if (networkInfo.getExtraInfo() != null) {
                    return networkInfo.getExtraInfo().replace("\"", "")
                }
            }
        }
        return ssid
    }


     override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

         appInit()
//        Log.d("====getMAC", getMAC("192.168.200.1"))

    }

    /**
     * 初始化函数
     *
     */
    @SuppressLint("SourceLockedOrientationActivity")
    fun appInit():Int {

        /*设置全屏模式*/
        if(windowManager.defaultDisplay.width <  windowManager.defaultDisplay.height){
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制横屏
        }
//        requestWindowFeature(Window.FEATURE_NO_TITLE)//需要在setContentView()之前设置

        supportActionBar?.hide()//隐藏标题栏

        /*设置全屏模式*/

        /*设置沉浸式主题*/
        if (Build.VERSION.SDK_INT >= 21) {

            var decorView = getWindow ().getDecorView();
            var option = (  View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or
                            View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR or
                            View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
                            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
                            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY );//or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN );

            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
//            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//设置状态栏图标和文字为深色

            //设置底部导航栏颜色
            /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
//                getWindow().setNavigationBarColor(ContextCompat.getColor(this,R.color.colorAccent));
            }*/

            setMaxAspect()


        }/*设置沉浸式主题*/

        setContentView(R.layout.activity_main)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            handlePermisson()

        }

        if (!(GPSisOpen(this)) ){
            /**/
            alert("Testing alerts") {
                title("GPS开启请求")
                message("前往打开GPS,否则部分功能会异常")
                yesButton {
                    var intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivityForResult(intent, 1);
                }
                noButton { }
            }.show()
            /**/
        }

        //权限
        getAppDetailSettingIntent()

        Log.d("______SSID:", getCurrentSsid(this));

        spinner.setSelection(0)//选中第1项
        spinner.onItemSelectedListener=object :AdapterView.OnItemSelectedListener {
            override fun onNothingSelected(parent: AdapterView<*>?) {
                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            }

            override fun onItemSelected(
                    parent: AdapterView<*>?,
                    view: View?,
                    position: Int,
                    id: Long) {
                spinner2.setSelection(spinner.selectedItemId.toInt())
            }

        }//监听下拉列表，使另一个列表同步

        if(!checkEnable(applicationContext)) Toast.makeText(applicationContext, "注意！网络不可用", Toast.LENGTH_LONG).show()//弹出消息

        textshow.movementMethod=ScrollingMovementMethod.getInstance()//设置可滚动
        textshow.setFocusable(true)
        textshow.setFocusableInTouchMode(true)//把焦点放在显示控件上
        textshow.setTextIsSelectable(true)

        pingMember = PingNetUtil()

        arpFun(false)//提前扫描内网
        if(!arpThread.isAlive)arpThread.start()

        tableShow?.isStretchAllColumns = true

        refalshVisible(UsingTool)

//        var aa= chart1 as LineChart
        myLinechart=lineChart(chart1)
        myPiechart=pieChart(chart2)

//        Log.d("WIFI________INFO",ObtainWifiInfo())

        return 0
    }

    /**
     *
     * 设置异形屏适配全屏
     *
     * */
    fun setMaxAspect() {
        // 延伸显示区域到刘海

            // 延伸显示区域到刘海
            val lp = window.attributes
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                lp.layoutInDisplayCutoutMode =
                    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
            }
            window.attributes = lp
            return
    }



    fun refalshVisible(useit: Tool){

        when(useit){
            Tool.PING -> {
                if (switch1.text == switch1.textOn) {
                    chart1.visibility = VISIBLE
                    chart2.visibility = VISIBLE
                    textshow.visibility = INVISIBLE
                    tableScoll.visibility = INVISIBLE

                } else if (switch1.text == switch1.textOff) {
                    chart1.visibility = INVISIBLE
                    chart2.visibility = INVISIBLE
                    textshow.visibility = VISIBLE
                    tableScoll.visibility = INVISIBLE

                }
            }
            Tool.ARP -> {

                chart1.visibility = INVISIBLE
                chart2.visibility = INVISIBLE
                textshow.visibility = INVISIBLE
                tableScoll.visibility = VISIBLE

            }
            Tool.NMAP -> {

                tableScoll.visibility = INVISIBLE
                textshow.visibility = VISIBLE
                chart1.visibility = INVISIBLE
                chart2.visibility = INVISIBLE
            }
            Tool.TRACETOUTE -> {
                if (switch1.text == switch1.textOn) {
                    switch1.isChecked = false
                    switch1.text = switch1.textOff
                }

                if (switch1.text == switch1.textOn) {
                    chart1.visibility = VISIBLE
                    chart2.visibility = VISIBLE
                    textshow.visibility = INVISIBLE
                    tableScoll.visibility = INVISIBLE

                } else if (switch1.text == switch1.textOff) {
                    chart1.visibility = INVISIBLE
                    chart2.visibility = INVISIBLE
                    textshow.visibility = VISIBLE
                    tableScoll.visibility = INVISIBLE
                }

            }


        }
    }


    fun rePress(useit: Tool){

        when(useit){
            Tool.PING -> {
                if (button4.text.toString() == resources.getString(R.string.button_stop)) { /*清除正在运行的traceRoute程序*/
                    traceRoute.clearProcess()
                    if (!traceRoute.isRun()) button4.text =
                            resources.getString(R.string.button_traceroute)
                }

                if (button.text.toString() == resources.getString(R.string.button_ping)) {
                    if (pingMember.isRun()) pingMember.clearProcess()//Toast.makeText(applicationContext,"正在扫描中，请稍后再试",Toast.LENGTH_LONG).show()//弹出消息
                    pingFun(editText.text.toString(), spinner.getSelectedItem().toString(), spinner2.getSelectedItem().toString())//初始化ping线程

                    textshow.text = editText.text.toString() + " Feedback:\n"//先把显示内容清空
                    textshow.scrollTo(0, 0);//将焦点位置放到起点上

                    myLinechart.reset()
                    myPiechart.recvPacket = 0
                    myPiechart.lossPacket = 0

                    pingThread.start()//开始运行ping线程
                } else if (button.text.toString() == resources.getString(R.string.button_stop)) {
                    if (pingMember.isRun()) pingMember.clearProcess()
                    button.text = resources.getString(R.string.button_ping)

                    /*发送到UI*/
                    var sendMsg = Message()
                    sendMsg.what = 9999
                    sendMsg.obj = "Operation interrupted!\n"
                    mHandler.sendMessage(sendMsg)

                }

            }
            Tool.ARP -> {
                if (pingMember.isRun()) pingMember.clearProcess()
                button.text = resources.getString(R.string.button_ping)

            }
            Tool.NMAP -> {
                if (pingMember.isRun()) pingMember.clearProcess()
                button.text = resources.getString(R.string.button_ping)
            }
            Tool.TRACETOUTE -> {
                if (pingMember.isRun()) pingMember.clearProcess()/*清除正在运行的Ping程序*/
                button.text = resources.getString(R.string.button_ping)

                if (button4.text.toString() == resources.getString(R.string.button_traceroute)) {
                    traceFun()
                    textshow.scrollTo(0, 0);//将焦点位置放到起点上
                    textshow.text = "Traceroute : \n"
                    traceThread.start()
                } else if (button4.text.toString() == resources.getString(R.string.button_stop)) {

                    traceRoute.clearProcess()
                    if (!traceRoute.isRun()) button4.text = resources.getString(R.string.button_traceroute)

                }
            }


        }
    }

    fun pingClicked(view: View) {

        KeyboardktUtils.hideKeyboard(view)/* 收起键盘 */

        if(editText?.text.toString()== "" || editText?.text.toString().isEmpty()) {
            Toast.makeText(applicationContext, "请输入地址", Toast.LENGTH_LONG).show()
            return
        }

        UsingTool=Tool.PING
        refalshVisible(UsingTool)
        rePress(UsingTool)

//        textshow?.setFocusable(true)
        textshow.setFocusableInTouchMode(true)//把焦点放在显示控件上



    }


    fun arpClicked(view: View) {

//        tableScoll.setFocusable(true)
//        tableScoll.setFocusableInTouchMode(true)//把焦点放在表格控件上
        UsingTool=Tool.ARP
        refalshVisible(UsingTool)
        rePress(UsingTool)

        Log.d("arp", "click")

        arpFun(true)
        if(!arpThread.isAlive)arpThread.start()//开始运行arp线程


    }


    fun nmapClicked(view: View) {

        Toast.makeText(applicationContext, "功能未上线", Toast.LENGTH_LONG).show()
        return

        UsingTool=Tool.NMAP
        refalshVisible(UsingTool)
        rePress(UsingTool)

        /*   if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)== PackageManager.PERMISSION_GRANTED) {
            //有权限

        }else{
            ActivityCompat.requestPermissions(this, []{Manifest.permission.CALL_PHONE},1);//无权限则询问开启权限

        }*/ //学习如何动态询问开启权限


    }

    fun traceClicked(view: View) {

        Log.d("traceRoute", "click")

        if(editText?.text.toString()== "" || editText?.text.toString().isEmpty()) {
            Toast.makeText(applicationContext, "请输入地址", Toast.LENGTH_LONG).show()
            return
        }

        UsingTool=Tool.TRACETOUTE
        refalshVisible(UsingTool)
        rePress(UsingTool)

    }

    fun focusClick(view: View) {

        KeyboardktUtils.hideKeyboard(view)//收起键盘
    }

    fun graphicClick(view: View){
        if(switch1.isChecked) {
            switch1.text = switch1.textOn
            if(UsingTool == Tool.PING)
                refalshVisible(Tool.PING)
        }else {
            switch1.text = switch1.textOff
            if(UsingTool == Tool.PING)
                refalshVisible(Tool.PING)
        }
    }



    private fun readArp() :Boolean{


        try {
            val br = BufferedReader(
                    FileReader("/proc/net/arp")
            )
            var line = ""
            var ip = ""
            var mac = ""

            while (br.readLine().also { line = it } != null) {
                try {
//                    Log.d("---/proc/net/arp",line)
                    line = line.trim { it <= ' ' }
                    if (line.length < 63) continue
                    if (line.toUpperCase(Locale.US).contains("IP")) continue
                    mac = line.substring(41, 63).trim { it <= ' ' }
                    ip=line.substring(0, 17).trim { it <= ' ' }
                    if (mac.contains("00:00:00:00:00:00")) continue
                    Log.d(
                            "scanner",
                            "readArp: mac= $mac ; ip= $ip"
                    )

//                    val map: Map<String, Object> = HashMap<String,Object>()
//                    map[arp]

                    val address = InetAddress.getByName(ip)
                    val reachable = address.isReachable(200)
                    var hostname:String = address.canonicalHostName

                    if (hostname == ip)hostname=""

//                    var arp ="$hostname\t$ip\t$mac\t$flag"
                    var arp ="$hostname\t$ip\t$mac"

                    /*发送给Handler*/
                    var sendMsg = Message()
                    sendMsg.what = ARPMSG
                    sendMsg.obj = arp
                    mHandler.sendMessage(sendMsg)
                    /*发送给Handler*/

//                    textshow.append(arp+'\n')
                } catch (e: Exception) {
                    continue
                }
            }
            br.close()

        } catch (e: Exception) {

            Log.e("Error", e.message)
            return false
        }
        return true
    }

/*    private fun ObtainWifiInfo(): String? {
        var result = ""
        val wifiManager =
            application.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val info = wifiManager.connectionInfo
        if (info.bssid != null) {
            //链接信号强度
            val strength = WifiManager.calculateSignalLevel(info.rssi, 5)
            //链接速度
            val speed = info.linkSpeed
            //链接速度单位
            val units = WifiInfo.LINK_SPEED_UNITS
            //Wifi源名称
            val ssid = info.ssid
            val ip = info.ipAddress
            val mac = info.macAddress
            result = strength.toString() + "|" + IntToIp(ip) + "|" + mac + "|" + ssid + "\n" + info
        }
        return result
    }

    private fun IntToIp(paramInt: Int): String {
        return (paramInt and 0xFF).toString() + "." + (0xFF and paramInt shr 8) + "." + (0xFF and paramInt shr 16) + "." + (0xFF and paramInt shr 24)
    }//获取WIFI的详细信息*/


    private fun getNetworkInfo():String {

        var wifi_str=""

        try {
            var mWifiManager =NULL;
            if (!checkEnable(applicationContext)) {
                Toast.makeText(applicationContext, "网络不可用", Toast.LENGTH_LONG).show();
                return "";
            }

            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O || Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
                mWifiManager = try {
                    this.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
                } catch (e: Exception) {
                    null
                }

                if (mWifiManager != null && mWifiManager.isWifiEnabled) {

                    val wifi = mWifiManager.connectionInfo
                    if (wifi.rssi != -200) {
//                    myIp = getWifiIPAddress(wifi.ipAddress)
                        myIp = getLocalIpAddress(applicationContext)
                    }
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                        myWifiName = wifi.ssid //获取被连接网络的名称
                    } else {
                        myWifiName = wifi.ssid.replace("\"", "");
                    }
                    myMac = wifi.bssid //获取被连接网络的mac地址
                    val str =
                        "WIFI: $myWifiName\t\t NetIP: $myIp\t\t MAC: $myMac"

                    var msg = Message()
                    msg.what = WIFIINFO
                    msg.obj = str
                    mHandler.sendMessage(msg)

                }
                if (!(mWifiManager != null && mWifiManager.isWifiEnabled) || myIp.contains("0.0.0.0")) {
                    myIp = getIpAddress()

                    var msg = Message()
                    msg.what = WIFIINFO
                    msg.obj = "NetIP:" + myIp
                    mHandler.sendMessage(msg)

                }
            }
            else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1){
                var mConnectivityManager = try {

                    this.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager;
                } catch (e: Exception) {
                    null
                }
                val wifi=mConnectivityManager?.activeNetworkInfo;
                myWifiName = wifi?.extraInfo?.replace("\"", "") //获取被连接网络的名称
                val str =
                    "WIFI: $myWifiName\t\t NetIP: $myIp\t\t MAC: $myMac"

                var msg = Message()
                msg.what = WIFIINFO
                msg.obj = str
                mHandler.sendMessage(msg)


            }//SSID无法获取,arp列表显示异常

            val address = InetAddress.getByName(myIp)
            val reachable = address.isReachable(200)
            var hostname:String = address.canonicalHostName

//            Log.d("________name",address.hostAddress+" ,"+address.hostName+" ,\n"+InetAddress.getByAddress("192.168.1.1"))
            wifi_str="$hostname\t$myIp\t$myMac"



        } catch (e: Exception) {
            e.message
        }
        return wifi_str

    }


    private fun discover(ip: String, timeout: Int) {

        var newip = ""

        val NBREQ = byteArrayOf(
                0x82.toByte(),
                0x28.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x1.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x20.toByte(),
                0x43.toByte(),
                0x4B.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x41.toByte(),
                0x0.toByte(),
                0x0.toByte(),
                0x21.toByte(),
                0x0.toByte(),
                0x1.toByte()
        )
        val NBUDPP: Int = 137

        if (ip != "") {
            var ipseg = ip.substring(0, ip.lastIndexOf(".") + 1)
//            Log.d("---debug",ipseg)
            var socket=DatagramSocket()
            var address: InetAddress
            var packet: DatagramPacket //单播

            for (i in 1..254) {
                newip = ipseg + i.toString()
                if (newip == null || newip == "") return
                try {

                    address = InetAddress.getByName(newip)

                    packet = DatagramPacket(
                            NBREQ,
                            NBREQ.size,
                            address,
                            NBUDPP
                    )
                    socket.soTimeout = timeout

                    socket.send(packet)
                    socket.send(packet)
                    socket.send(packet)



                } catch (se: SocketException) {
                } catch (e: UnknownHostException) {
                } catch (e: IOException) {
                } finally {
                }

                if (i == 51 || i == 102 || i == 152 || i== 203) {//分五段发包，一次性发的话，达到236左右，会耗时3秒左右再往下发
                    socket.close()
                    socket =  DatagramSocket()
                }

                var per:Int= (i*100/254)

                var msg = Message()
                msg.what = ARPPER
                msg.obj = per.toString()
                mHandler.sendMessage(msg)

            }
            socket.close()
        }
    }

    private fun   getWifiIPAddress(ipaddr: Int): String {
//        Log.d("try","getWifiIPAddress")

        var ip = ""
        if (ipaddr == 0) return ip
        val addressBytes = byteArrayOf(
                (0xff and ipaddr).toByte(), (0xff and (ipaddr shr 8)).toByte(),
                (0xff and (ipaddr shr 16)).toByte(), (0xff and (ipaddr shr 24)).toByte()
        )
        try {
            ip = InetAddress.getByAddress(addressBytes).toString()
            ip = if (ip.length > 1) {
                ip.substring(1, ip.length)
            } else {
                ""
            }
        } catch (e: UnknownHostException) {
            ip = ""
        } catch (e: Exception) {
            ip = ""
        }
        return ip
    }


    //GPRS连接下的ip
    fun getIpAddress(): String {

        try {
            val en =
                NetworkInterface.getNetworkInterfaces()
            while (en.hasMoreElements()) {

                val intf = en.nextElement()
                val enumIpAddr = intf.inetAddresses
                while (enumIpAddr.hasMoreElements()) {
//                    Log.w("getIpAddress()","enumIpAddr.nextElement()")
                    val inetAddress = enumIpAddr.nextElement()
                    if (!inetAddress.isLoopbackAddress) {
                        return inetAddress.hostAddress.toString()
                    }
                }
            }
        } catch (ex: SocketException) {
            Log.e("WifiIpAddress", ex.message)
        }
        return ""
    }

    /**
     * 检查网络是否可用
     *
     * @param paramContext
     * @return
     */
    @SuppressLint("WrongConstant")
    fun checkEnable(paramContext: Context): Boolean {

        val localNetworkInfo = (paramContext
            .getSystemService("connectivity") as ConnectivityManager).activeNetworkInfo
        return if (localNetworkInfo != null && localNetworkInfo.isAvailable) true else false
    }

    /**
     * 获取当前ip地址
     *
     * @param context
     * @return
     */
    private fun  getLocalIpAddress(context: Context): String {
        try {
            var IP:String=""

            var wifiManager :WifiManager =
                context.getSystemService(Context.WIFI_SERVICE) as WifiManager
            var wifiInfo :WifiInfo = wifiManager.getConnectionInfo()
             var ip:Int = wifiInfo.getIpAddress()
            IP=int2ip(ip)
            return IP
        } catch (ex: Exception) {
            return "0.0.0.0" + ex.message
        }
        // return null;
    }

    fun int2ip(ipInt: Int): String {
        val sb = StringBuilder()
        sb.append(ipInt and 0xFF).append(".")
        sb.append(ipInt shr 8 and 0xFF).append(".")
        sb.append(ipInt shr 16 and 0xFF).append(".")
        sb.append(ipInt shr 24 and 0xFF)
        return sb.toString()
    }


}



/**
 * 线性图表
 * 参考 https://blog.csdn.net/guijiaoba/article/details/41444697
 *      https://www.jianshu.com/p/c6e8ea5e9ba0
 * */
class lineChart constructor(mychart: LineChart){
    private var mChart:LineChart
    private var values: ArrayList<Entry>
    private lateinit var set1: LineDataSet
    var packCount:Int = 0


    init{
        mChart = mychart
        mChart.setDrawGridBackground(false)

        mChart.setDescription("")
        mChart.setNoDataTextDescription("wating for Response.")

        // enable touch gestures
        mChart.setTouchEnabled(true)

        // enable scaling and dragging
        mChart.setDragEnabled(true)
        mChart.setScaleEnabled(true)

        // if disabled, scaling can be done on x- and y-axis separately
        mChart.setPinchZoom(true)

        // 获取lineCahrt图列
        val l: Legend = mChart.legend
        l.setEnabled(true) //是否启用图列（true：下面属性才有意义）
        l.setForm(Legend.LegendForm.CIRCLE) //设置图例的形状

        values=ArrayList()


    }
    /**
     * 重设数组数据
     *
     * */
    fun reset(){
        packCount=0
        values.clear()
    }
    /**
     * 设置模拟数据
     * @param count 数据的
     * @param data 数据的值
     */
     fun setData(count: Int, data: Float) {

        if(count > 0 && count < packCount + 1){
            values.set(count, Entry(count.toFloat(), data))
        } else{
            if (count == packCount + 1) {
    //        values.add(Entry(count.toFloat(), data))
//                mChart.setVisibleXRange( if(count>10) (count-10f) else 0f,count.toFloat())
                packCount = count
            } else if (count > packCount + 1) {
                for (i in (packCount + 1) until count) {
                    values.add(i, Entry(i.toFloat(), 0f))
                }
                packCount = count
            }
            values.add(count, Entry(count.toFloat(), data))

            /*val xl: XAxis = mChart.getXAxis()
            xl.setAxisMinValue(0f)
            xl.setAxisMaxValue(values.size.toFloat())
            mChart.setVisibleXRange(if(count>9) (count-8f) else 0f,8f)*///限制页面显示个数,需要滑动显示全部
        }

        /**把上面四个if 整合成一个if else里面再细分 , 因为values.add()语句冗余了 */
        if (mChart.getData() != null &&
            mChart.getData().getDataSetCount() > 0)
        {
//            Log.d("chart","if--------")
            set1 = mChart.getData().getDataSetByIndex(0) as LineDataSet
            set1.setValues(values)
            mChart.getData().notifyDataChanged()
            mChart.notifyDataSetChanged()
        } else {
//            Log.d("chart","else--------")
            // create a dataset and give it a type
            set1 = LineDataSet(values, mChart.context.getString(R.string.response_time))

            // set the line to be drawn like this "- - - - - -"
            set1.enableDashedLine(10f, 5f, 0f)
            set1.enableDashedHighlightLine(10f, 5f, 0f)
            set1.setColor(Color.BLACK)
            set1.setCircleColor(Color.BLACK)
            set1.setLineWidth(1f)
            set1.setCircleRadius(3f)
            set1.setDrawCircleHole(false)
            set1.setValueTextSize(12f)
            set1.setDrawFilled(true)


        }

        val dataSets: ArrayList<ILineDataSet> = ArrayList<ILineDataSet>()
        dataSets.add(set1) // add the datasets

        // create a data object with the datasets
        val datas = LineData(dataSets)

        // set data
        mChart.setData(datas)
        mChart.invalidate()
    }
}

/**
 * 饼状图表
 * 参考 https://blog.csdn.net/guijiaoba/article/details/41444697
 *      https://www.jianshu.com/p/c6e8ea5e9ba0
 *      https://blog.csdn.net/zcmain/article/details/53611245
 * */
class pieChart constructor(mychart: PieChart){
    private var mChart:PieChart
    private var values: ArrayList<PieEntry>
    private lateinit var dataSet: PieDataSet
    var lossPacket:Int = 0
    var recvPacket:Int = 0


    init{
        mChart = mychart

        mChart.setDescription("")

        // enable touch gestures
        mChart.setTouchEnabled(true)
        mChart.setUsePercentValues(true)
        mChart.setDrawEntryLabels(true)
        values=ArrayList()


        //--------------------------------


        // 获取pieCahrt图列
        val l: Legend = mChart.legend
        l.setEnabled(true) //是否启用图列（true：下面属性才有意义）

        l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP)
        l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT)
        l.setOrientation(Legend.LegendOrientation.VERTICAL)
        l.setForm(Legend.LegendForm.CIRCLE) //设置图例的形状为圆形

        l.setFormSize(10f) //设置图例的大小
        l.setTextSize(12f) //设置图例标签文本的大小

        l.setDrawInside(false)
        l.setWordWrapEnabled(true) //设置图列换行(注意使用影响性能,仅适用legend位于图表下面)

        l.setXEntrySpace(8f) //设置图例实体之间(X轴)的间距（setOrientation = HORIZONTAL有效）

//        l.setYOffset(50f) //设置比例块Y轴偏移量
        l.setXOffset(20f) //设置比例块X轴偏移量


//        l.setTextColor(Color.parseColor("#ff9933")) //设置图例标签文本的颜色


    }
    /**
     * 设置模拟数据
     * @param count 数据的
     * @param date 数据的值
     */
    fun setData() {

//        Log.d("data","lossPacket "+lossPacket)
        values.clear()

         if(recvPacket > 0)
             values.add(PieEntry(recvPacket.toFloat(), mChart.context.getString(R.string.received)))

         if(lossPacket > 0)
             values.add(PieEntry(lossPacket.toFloat(), mChart.context.getString(R.string.loss)))




        if (mChart.getData() != null &&
            mChart.getData().getDataSetCount() > 0)
        {
            dataSet = mChart.getData().getDataSetByIndex(0) as PieDataSet
            dataSet.setValues(values)
            mChart.getData().notifyDataChanged()
            mChart.notifyDataSetChanged()
        } else {
            // create a dataset and give it a type
            val label: ArrayList<String> = ArrayList()
            dataSet = PieDataSet(values, "")
            val colors: ArrayList<Int> = ArrayList()
            colors.add(Color.parseColor("#339900"))//绿
            colors.add(Color.parseColor("#ee6e55"))//红
            dataSet.setColors(colors)
            dataSet.setValueFormatter(PercentFormatter());
            dataSet.setValueTextSize(12f)

            //把百分比显示到饼状图外围
            dataSet.valueLinePart1OffsetPercentage=80f
            dataSet.valueLinePart1Length=0.3f
            dataSet.valueLinePart2Length=0.4f
            dataSet.yValuePosition=PieDataSet.ValuePosition.OUTSIDE_SLICE

            /*var legend = mChart.getLegend()
//            legend.setEnabled(true)
            legend.setForm(Legend.LegendForm.SQUARE);*/


        }

        // create a data object with the dataset
        var data = PieData(dataSet)
        data.setDrawValues(true)

        // set data
        mChart.setData(data)
        mChart.invalidate()
    }
}


/**
 * 1.需要一个函数,在每项功能运行之前,先把别的功能后台程序关掉,以免影响显示 OK
 * 2.需要加一个饼状图形,显示数据丢失率  图例文字不显示 OK
 * 3.需要在切换其他功能界面的时候,将switch开关切换成文字显示的模式   OK
 * 4.子网列表加入自己的IP 和MAC     OK
 * 5.去除多余Log    OK
 * 6.在不知IP是否通的情况下,直接获取该IP 的名称(4项使用了该功能并且成功),看是否可行  NO
 * 采取跳转到某页面,手动打开权限的方法
 * 查查分散对齐的方法    OK
 *
 *https://www.jianshu.com/p/802118e621d6
 * https://blog.csdn.net/zcmain/article/details/53611245
 *
 * 文件管理器
 * https://baijiahao.baidu.com/s?id=1627986611418147934&wfr=spider&for=pc
 * */